console.log("[vite] connecting...");
const socket = new WebSocket(`ws://localhost:__HMR_PORT__`, "vite-hmr");
socket.addEventListener("message", async ({ data }) => {

  handleMessage(JSON.parse(data)).catch(console.error)

})
async function handleMessage(payload: any) {
  switch (payload.type) {
    case "connected":
      console.log("[vite] connected.")
      setInterval(() => {
        socket.send("ping")
      }, 1000)
      break
    case "update":
      payload.updates.forEach((update: any) => {
        if (update.type === "js-update") {

          fetchUpdate(update);


        }
      })
  }
}
interface HotModule {
  id: string;
  callbacks: HotCallback[]
}
interface HotCallback {
  deps: string[];
  fn: (modules: object[]) => void
}
const hotModulesMap = new Map<string, HotModule>();
const pruneMap = new Map<string, (data: any) => void | Promise<void>>();
const sheetsMap = new Map();
export const createHotContext = (ownerPath: string) => {
  const mod = hotModulesMap.get(ownerPath);
  console.log("ownerPath", ownerPath)
  if (mod) {
    mod.callbacks = []
  }

  function acceptDeps(deps: string[], callback: (modules: object[]) => void) {

    const mod: HotModule = hotModulesMap.get(ownerPath) || { id: ownerPath, callbacks: [] }
    mod?.callbacks.push({ deps, fn: callback })
    hotModulesMap.set(ownerPath, mod);
    console.log("ownerPath", ownerPath, mod)

  }

  return {
    accept(deps: any) {
      console.log(typeof deps === "function")

      if (typeof deps === "function" || !deps) {
        console.log("deps", deps)
        acceptDeps([ownerPath], ([mod]) => deps && deps(mod));
      }
    },
    prune(cb: (data: any) => void) {
      pruneMap.set(ownerPath, cb);
    },

  }



}
async function fetchUpdate({ path, timestamp }: any) {
  // console.log(path, hotModulesMap)
  const mod = hotModulesMap.get(path);
  console.log(mod, hotModulesMap)
  if (!mod) return;
  console.log("mod", mod)
  const moduleMap = new Map();
  const modulesToUpdate = new Set<string>();
  modulesToUpdate.add(path);
  console.log("modulesToUpdate", modulesToUpdate, path)
  await Promise.all(
    Array.from(modulesToUpdate).map(async (dep) => {
      const [path, query] = dep.split(`?`);
      console.log("dep", dep, path, timestamp)
      try {
        // 通过动态 import 拉取最新模块
        const newMod = await import(
          path + `?t=${timestamp}${!!query ? `&${query}` : ""}`
        );

        moduleMap.set(dep, newMod);
        console.log(moduleMap)
      } catch (e) { }
    })
  );

  return () => {
    // 拉取最新模块后执行更新回调
    for (const { deps, fn } of mod.callbacks) {
      fn(deps.map((dep: any) => moduleMap.get(dep)));
    }
    console.log(`[vite] hot updated: ${path}`);
  };
}
export function updateStyle(id: string, content: string) {
  let style = sheetsMap.get(id);
  if (!style) {
    style = document.createElement("style")
    style.setAttribute("type", "text/css");
    style.innerHTML = content;
    document.head.appendChild(style);
  } else {
    style.innerHTML = content;
  }
  sheetsMap.set(id, style)
}
export function removeStyle(id: string): void {
  const style = sheetsMap.get(id);
  if (style) {
    document.head.removeChild(style);
  }
  sheetsMap.delete(id);
}